namespace srl {

    template<class T> Matrix<T>::Matrix() {}
    template<class T> Matrix<T>::Matrix(srl::Matrix<T> *Mat) { Values = Mat.Values; }
    template<class T> Matrix<T>::~Matrix() {}
    
    
    template<class T>
    srl::Matrix<T> Matrix<T>::operator= (srl::Matrix<T> &Mat) {
        Values = Mat.Values;
        return (*this);
    }
     
    template<class T>
    srl::Matrix<T> Matrix<T>::operator* (srl::Matrix<T> &Mat) {
        Matrix<T> Final;
    
        Final.Values[0]  = (Values[0]  * Mat.Values[0])  +  (Values[1]  * Mat.Values[4])  +  (Values[2]  * Mat.Values[8] )  +  (Values[3]  * Mat.Values[12]);
        Final.Values[1]  = (Values[0]  * Mat.Values[1])  +  (Values[1]  * Mat.Values[5])  +  (Values[2]  * Mat.Values[9] )  +  (Values[3]  * Mat.Values[13]);
        Final.Values[2]  = (Values[0]  * Mat.Values[2])  +  (Values[1]  * Mat.Values[6])  +  (Values[2]  * Mat.Values[10])  +  (Values[3]  * Mat.Values[14]);
        Final.Values[3]  = (Values[0]  * Mat.Values[3])  +  (Values[1]  * Mat.Values[7])  +  (Values[2]  * Mat.Values[11])  +  (Values[3]  * Mat.Values[15]);
    
        Final.Values[4]  = (Values[4]  * Mat.Values[0])  +  (Values[5]  * Mat.Values[4])  +  (Values[6]  * Mat.Values[8] )  +  (Values[7]  * Mat.Values[12]);
        Final.Values[5]  = (Values[4]  * Mat.Values[1])  +  (Values[5]  * Mat.Values[5])  +  (Values[6]  * Mat.Values[9] )  +  (Values[7]  * Mat.Values[13]);
        Final.Values[6]  = (Values[4]  * Mat.Values[2])  +  (Values[5]  * Mat.Values[6])  +  (Values[6]  * Mat.Values[10])  +  (Values[7]  * Mat.Values[14]);
        Final.Values[7]  = (Values[4]  * Mat.Values[3])  +  (Values[5]  * Mat.Values[7])  +  (Values[6]  * Mat.Values[11])  +  (Values[7]  * Mat.Values[15]);
    
        Final.Values[8]  = (Values[8]  * Mat.Values[0])  +  (Values[9]  * Mat.Values[4])  +  (Values[10] * Mat.Values[8] )  +  (Values[11] * Mat.Values[12]);
        Final.Values[9]  = (Values[8]  * Mat.Values[1])  +  (Values[9]  * Mat.Values[5])  +  (Values[10] * Mat.Values[9] )  +  (Values[11] * Mat.Values[13]);
        Final.Values[10] = (Values[8]  * Mat.Values[2])  +  (Values[9]  * Mat.Values[6])  +  (Values[10] * Mat.Values[10])  +  (Values[11] * Mat.Values[14]);
        Final.Values[11] = (Values[8]  * Mat.Values[3])  +  (Values[9]  * Mat.Values[7])  +  (Values[10] * Mat.Values[11])  +  (Values[11] * Mat.Values[15]);
    
        Final.Values[12] = (Values[12] * Mat.Values[0])  +  (Values[13] * Mat.Values[4])  +  (Values[14] * Mat.Values[8] )  +  (Values[15] * Mat.Values[12]);
        Final.Values[13] = (Values[12] * Mat.Values[1])  +  (Values[13] * Mat.Values[5])  +  (Values[14] * Mat.Values[9] )  +  (Values[15] * Mat.Values[13]);
        Final.Values[14] = (Values[12] * Mat.Values[2])  +  (Values[13] * Mat.Values[6])  +  (Values[14] * Mat.Values[10])  +  (Values[15] * Mat.Values[14]);
        Final.Values[15] = (Values[12] * Mat.Values[3])  +  (Values[13] * Mat.Values[7])  +  (Values[14] * Mat.Values[11])  +  (Values[15] * Mat.Values[15]);
    
        return Final;
    }
    
    template<class T>
    srl::Vector<T> Matrix<T>::operator* (srl::Vector<T> &Vec) {
        Vector<T> Final;
        
        Final[0] = Vec.x * (Values[0] + Values[1] + Values[2] + Values[3]);
        Final[1] = Vec.y * (Values[4] + Values[5] + Values[6] + Values[7]);
        Final[2] = Vec.z * (Values[8] + Values[9] + Values[10] + Values[11]);
        
        return Final;
    }
    
    template<class T>
    srl::Matrix<T>& Matrix<T>::operator*= (srl::Matrix<T> &Mat) {
        (*this) = (*this) * Mat;
        return this;
    }
    
    template<class T>
    T* Matrix<T>::Get() {
        return Values;
    }
    
    template<class T>
    srl::Vector<T> Matrix<T>::operator[](int i) {
    	return srl::Vector<T>(Values[(i-1)*4], Values[(i-1)*4+1], Values[(i-1)*4+2], Values[(i-1)*4+3]);
    }
    
    template<class T>
    T Matrix<T>::operator()(int i) {
        return Values[i];
    }
    
};
